package com.gitee.apanlh.util.net.http;

import com.gitee.apanlh.exp.HttpException;
import com.gitee.apanlh.exp.ParseException;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.id.IdUtils;
import com.gitee.apanlh.util.reflection.ClassTypeUtils;
import com.gitee.apanlh.util.reflection.ClassUtils;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.web.http.HttpMethod;

import java.util.Map;

/**	
 * 	请求体、返回体Body
 * 	
 * 	@author Pan
 */
public class HttpBody {
	
	/** httpRequest对象 */
	private HttpRequest httpRequest;
	/** 请求体 */
	private Object requestBody;
	/** 请求类型 */
	private HttpBodyTypeEnum bodyType;
	/** FORM_DATA分隔符 */
	private String formDataBoundary;
	/** 是否默认传递就位解析过的，如withJson传递String */
	private boolean parameterParse;
	
	/**
	 * 	默认构造函数
	 * 	
	 * 	@author Pan
	 */
	HttpBody() {
		super();
	}
	
	/**	
	 * 	构造函数-加载HttpRequest对象
	 * 	
	 * 	@author Pan
	 * 	@param 	httpRequest	httpRequest对象
	 */
	public HttpBody(HttpRequest httpRequest) {
		this.httpRequest = httpRequest;
	}
	
	/**	
	 * 	获取FORM_DATA分隔符
	 * 	<br>如果不存在则生成FORM_DATA分隔符
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public String getFormDataBoundary() {
		if (formDataBoundary == null) {
			this.formDataBoundary = StringUtils.append("--------PAN#FormData#", IdUtils.generateIdStr());
		}
		return formDataBoundary;
	}

	/**	
	 * 	获取-请求体类型
	 * 	
	 * 	@author Pan
	 * 	@return	HttpBodyTypeEnum
	 */
	public HttpBodyTypeEnum getBodyType() {
		return bodyType;
	}

	/**	
	 * 	获取-请求体内容
	 * 
	 * 	@author Pan
	 * 	@return	Object	请求体内容
	 */
	public Object getRequestBody() {
		return requestBody;
	}
	
	/**	
	 * 	设置传递参数是否为已解析
	 * 
	 * 	@author Pan
	 * 	@param 	hasParse	标识
	 */
	public void setParameterParse(boolean hasParse) {
		this.parameterParse = hasParse;
	}
	
	/**	
	 * 	是否参数已解析标识
	 * 
	 * 	@author Pan
	 * 	@return	boolean	
	 */
	public boolean hasParameterParse() {
		return this.parameterParse;
	}
	
	/**	
	 * 	获取-是否QueryParams数据格式
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public boolean hasQueryParams() {
		return Eq.enums(HttpBodyTypeEnum.QUERY_PARAMS, this.bodyType);
	}
	
	/**	
	 * 	获取-是否Form数据格式
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public boolean hasForm() {
		return Eq.enums(HttpBodyTypeEnum.FORM, this.bodyType);
	}
	
	/**	
	 * 	获取-是否FormData数据格式
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public boolean hasFormData() {
		return Eq.enums(HttpBodyTypeEnum.FORM_DATA, this.bodyType);
	}
	
	/**	
	 * 	获取-是否JSON数据格式
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public boolean hasJson() {
		return Eq.enums(HttpBodyTypeEnum.JSON, this.bodyType);
	}

	/**	
	 * 	获取-是否RESTful风格
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public boolean hasRest() {
		return Eq.enums(HttpBodyTypeEnum.PATH_VARIABLE, this.bodyType);
	}
	
	/**	
	 * 	获取-是否RESTful风格 URL资源形式
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public boolean hasPathVariable() {
		return Eq.enums(HttpBodyTypeEnum.PATH_VARIABLE, this.bodyType);
	}
	
	/**
	 * 	请求体是否Map类型
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public boolean isRequestBodyMap() {
		return requestBody instanceof Map;
	}
	
	/**	
	 * 	设置请求体
	 * 	
	 * 	@author Pan
	 * 	@param 	requestBody 请求体
	 */
	public void setRequestBody(Object requestBody) {
		this.requestBody = requestBody;
	}
	
	/**
	 * 	检测填充请求体的方法是否正确
	 * 	
	 * 	@author Pan
	 */
	private void checkWithBodyMethod() {
		//	字节请求验证
		if (Eq.enums(HttpMethod.GET, httpRequest.getMethod())) {
			throw new HttpException("with body error cause: request method error , please use the [POST] method");
		}
		
		//	Restful请求方式验证
		if (Eq.enums(HttpMethod.GET, httpRequest.getMethod()) && !httpRequest.getConfig().hasHasEnableRest()) {
			throw new HttpException("with body error cause: request method error, please use the [withQueryParams()] method");
		}
	}
	
	/**
	 * 	检测填充请求体类型是否正确
	 * 	
	 * 	@author Pan
	 */
	private void checkWithBodyType() {
		Class<?> clazz = requestBody.getClass();
		//	增加对基本数据及String类型验证判断
    	if (ClassTypeUtils.isBasicDataType(clazz) || ClassTypeUtils.isString(clazz)) {
    		//	放行JSON类型
    		if (hasJson()) {
    			return ;
    		}
    		throw new ParseException(StringUtils.format("type [{}] cannot be parsed", ClassUtils.getSimpleName(clazz)));
    	}
	}
	
	/**
	 * 	填充-请求对象数据
	 *  <br>此时是未处理的原始对象
	 *  <br>自定义请求方式
	 *  <br>将会检测数据及方法合法性
	 *  	
	 * 	@author Pan
	 * 	@param 	requestBody	请求体内容
	 * 	@param 	bodyType	请求体类型
	 * 	@return	HttpBody
	 */
	<T> HttpBody withBody(T requestBody, HttpBodyTypeEnum bodyType) {
		this.bodyType = bodyType;
		setRequestBody(requestBody);

		//	添加GET请求放行
		if (Eq.enums(HttpMethod.GET, httpRequest.getMethod())) {
			return this;
		}

		//	检查数据合法性
		Assert.isNotNull(requestBody);
		//	检测方法合法性
		checkWithBodyMethod();
		//	检测数据类型合法性
		checkWithBodyType();
		return this;
	}

	/**	
	 * 	构建HTTPBody对象
	 * 	<br>自定义请求对象
	 * 	<br>自定义请求类型
	 * 	
	 * 	@author Pan
	 * 	@param  <T>      	数据类型
	 * 	@param 	httpRequest	httpRequest对象
	 * 	@param 	requestBody	请求体对象
	 * 	@param 	bodyType	请求体类型
	 * 	@return	HttpBody
	 */
	public static <T> HttpBody create(HttpRequest httpRequest, T requestBody, HttpBodyTypeEnum bodyType) {
		return new HttpBody(httpRequest).withBody(requestBody, bodyType);
	}
}
